'''
Business logic for pyknobjex

ADAP HIS
-fill table Relations temp with tree-recs
    v-check msaccess-code
    v-create pseudo-code
    v-delete temp-recs before requery
    v-better performance
    -add sortPath
        -maximize
-delete rel-recs based on temp-recs
-implement abort when new stem is in own branche

ADAP NO

ADAP FU
'''


import db_species
##import jodb
import pardb
import jotools
import jocallback


leftdepthit = 0
rightdepthit = 0
parentnumit = 0
childrennumit = 0

globrowtotal = 0
globrowcount = 0


##relsqueryst = 'FDQ_RELATIONS_SORTED3'

def readBrancheToTable(relsqueryst, parentvalst, directionst, maxdepthit,
    deletepreviousbo = True, sortprefixst='', calculatepathwaybo= False,
    includemultiparentbo = True):

    '''
    UNIT INFO
    Read all child-recs for parentvalst and them to table TempRelations.
    special params:
        directionst
            query left or right objects
        deletepreviousbo = True, sortprefixst=''
             are added for function readMultipleBranchesToTable.
        calculatepathwaybo= False
            to calculate pathways to expand the tree to specific child
        includemultiparentbo - true on default
            set false if you want that only records are added for objects
            that have one parent at most. This is to prevent deletions
            of branches that are shared with other trees that you dont
            want to delete.


    ADAP HIS
    -enable exclusion of multi-parent objects (also in readBrancheCycle)
        v-add param
        -adjust the code
            v-re-understand the current code
            v-reckon with query-direction
        v-adjust all calls
        -update unit-info

    ADAP NO
    '''

    if deletepreviousbo: deleteTempRelations()
    relsfieldli = pardb.getFieldList('',relsqueryst)
    datatypedi = pardb.getDataTypeDict('', relsqueryst)
##        print datatypedi
##    print datetime.now()
    readBrancheCycle(relsqueryst, parentvalst, directionst , maxdepthit, 0,
            relsfieldli, datatypedi, sortprefixst,calculatepathwaybo,
            includemultiparentbo)
##    print datetime.now()

def readBrancheCycle(relsqueryst, parentvalst, directionst, maxdepthit, depthit,
        relsfieldli,datatypedi, sortpathst='',calculatepathwaybo=False,
        includemultiparentbo = True):
    '''
    -filter the relation-records for the given parent-value and
    write them to the table RelationsTemp.
    -do it recursively to build all the tree-records
    '''

    # get cursor with root as parent depending on direction
    if directionst == 'rightobjects':
        parentfieldst = 'Object1'
        childfieldst = 'Object2'
    elif directionst == 'leftobjects':
        parentfieldst = 'Object2'
        childfieldst = 'Object1'

    curli2 = pardb.readFromParams('', relsqueryst,None,
        {'strings':{parentfieldst:parentvalst}})
    # write every row to the temp-table
    rowit = 0
    for rowli in curli2:
        # --------code-start for multiparent------------
        proceedbo = False
        if includemultiparentbo:
       	    proceedbo = True
        else:
        	# proceed only if the child has not multiple parents
            childvaluest = rowli[relsfieldli.index(childfieldst)]
            parentcountit = pardb.rowCountFromParams('', relsqueryst,None,
                    {'strings':{childfieldst:childvaluest}})
##            print 'parentcountit = ' + str(parentcountit)
            if parentcountit < 2:
                proceedbo = True

        if proceedbo == True:
        # -----------code-end for multiparent----------------

            fieldvaluedi = {}
            for fieldst in relsfieldli:
    ##            print fieldst
                datatypest = datatypedi[fieldst]
                val = rowli[relsfieldli.index(fieldst)]
                if not str(val) == 'None':
                    if str(type(val)) == "<type 'unicode'>":
                        # convert unicode to string
                        val = val.encode('latin-1')
                    if datatypest == "<type 'datetime.datetime'>":
                        fieldvaluedi[fieldst]= str(val)
                    elif datatypest == "<type 'float'>":
                        fieldvaluedi[fieldst]= float(val)
                    else:
                        fieldvaluedi[fieldst]= val

            # add a sort-path or pathway of relID's
            if not calculatepathwaybo:
                followit = rowit
                if rowit > 25: followit = 25 # maximize to 'z'
                newsortpathst = sortpathst + chr(97 + followit)
                fieldvaluedi['SortString'] = newsortpathst
            else:
                relidit = rowli[relsfieldli.index('RelID')]
                fieldvaluedi['RelID'] = relidit
                if sortpathst == '':
                    newsortpathst = str(relidit)
                else:
                    newsortpathst = sortpathst + '-' + str(relidit)
                fieldvaluedi['MsLongText'] = newsortpathst

            # add depth
            fieldvaluedi['Depth'] = depthit

            # create new record based on dict
            pardb.addnewFromParams('', 'RelationsTemp',fieldvaluedi)
            # recurse the action conditionally
            childvalst = rowli[relsfieldli.index(childfieldst)]
            if depthit < maxdepthit:
                if not newObjectAllreadyAdded(childvalst, directionst):
                    readBrancheCycle(relsqueryst ,childvalst, directionst,
                         maxdepthit, depthit + 1,
                        relsfieldli, datatypedi, newsortpathst,
                        calculatepathwaybo, includemultiparentbo)
            rowit = rowit + 1

def newObjectAllreadyAdded(childvalst, directionst):
    # in case of structure that is not a pure tree but a network,
    # that means a child has more parents, you want that object-tree
    # only one time.

    if directionst == 'rightobjects':
        parentfieldst = 'Object1'
        childfieldst = 'Object2'
    elif directionst == 'leftobjects':
        parentfieldst = 'Object2'
        childfieldst = 'Object1'

    rowcountit = pardb.rowCountFromParams('', 'RelationsTemp',None,
        {'strings':{parentfieldst:childvalst}})
    addedbo = False
    if rowcountit > 0: addedbo = True
    return addedbo

def deleteTempRelations():
    pardb.deleteAllFromTable('', 'RelationsTemp')

def doMatchingRelations(actionst, selcritdi=None, updatecritdi=''):
    '''
    Actionst can be delete or update of the records.
    For update addtional criteria are needed.
    '''
    cursorli = pardb.readFromParams('', 'RelationsTemp', ['RelID'], selcritdi)
    for rowli in cursorli:
        for val in rowli:
            if actionst == 'delete':
                pardb.deleteFromParams('', 'Relations', {'numbers':{'RelID':val}})
            elif actionst == 'update':
                pardb.updateFromParams('', 'Relations', updatecritdi,
                                    {'numbers':{'RelID':val}})


def readMultipleBranchesToTable(changevalst):

    deleteTempRelations()
    # query all the stems on basis of change-field
    cursorli = pardb.readFromParams('', 'FDQ_RELATIONS_CHANGE', ['Object2'],
        {'subs':{'Change':changevalst}})
    # for each stem do read the branche
    countit = 0
    for rowli in cursorli:
        countit = countit + 1
        if countit < 10:
            countprefixst = '0' + str(countit)
        else:
            countprefixst = str(countit)
        stemst = str(rowli[0])
        sortprefixst = countprefixst + '-' + stemst[:4] + '  '
        querydepthit = readOption('export_branches_query_depth')
        readBrancheToTable('FDQ_RELATIONS_SORTED3_OPEN',stemst, 'rightobjects',
            querydepthit ,False, sortprefixst)

def updateHistoryTable(newitemst):
    '''
    UNIT INFO
    -delete the oldest record if max number of records is about to exceed
    -add new item to the table (table contains a time-field for ordering)
     '''

    maxHistoLengthit = 60
    if pardb.rowCountFromParams('', 'History') > maxHistoLengthit:
        oldestRecTimest = pardb.readFromParams('', 'FDQ_HISTORY_OLDEST')[0][0]
        pardb.deleteFromParams('', 'History',{'datetimes':{'Time':oldestRecTimest}})

    if db_species.db_typest == 'ms access 2000':
        pardb.addnewFromParams('', 'History',{'Object':str(newitemst)})
    elif db_species.db_typest == 'sqlite3':
        pardb.addnewFromParams('', 'History',{'Object':str(newitemst),
                                'Time':jotools.currentDateTime()})
##        pardb.addnewFromParams('', 'History',{'Object':newitemst,
##                                'Time':jotools.currentDateTime()})


def calculatePathway(sourceobjectst, targetobjectst, directionst,
            searchdepthit):
    '''
    ADAP NO
    '''

    readBrancheToTable('FDQ_RELATIONS_SORTED3', sourceobjectst,
        directionst, searchdepthit, True, '', True)
    countit = pardb.rowCountFromParams('', 'RelationsTemp',None,
            {'strings':{'object2': targetobjectst}})
    if countit > 0:
        returnbo = True
        pardb.deleteAllFromTable('', 'PATHWAYS')
        curli = pardb.readFromParams('', 'RelationsTemp',None,
                {'strings':{'object2': targetobjectst}})
        fieldli = pardb.getFieldList('', 'RelationsTemp')
        print curli
        print fieldli
        indexit = fieldli.index('MsLongText')
        print indexit
        pathwayst = str(curli[0][indexit])
        print pathwayst
        pathwayli = pathwayst.split('-')
        print pathwayli
        for relidit in pathwayli:
            pardb.addnewFromParams('', 'PATHWAYS', {'PATHWAY':'test','RELID':relidit})
    else:
        print 'path not found'
        returnbo = False

    print sourceobjectst + ' - ' + targetobjectst

    return returnbo

def readOption(paramidst, scopest = 'db'):

    if scopest == 'db':
        rowdi = pardb.readDictFromParams('', 'PARAMS', None,
                        {'strings':{'ParamID':paramidst}})
    elif scopest == 'sys':
        rowdi = pardb.readDictFromParams(db_species.settingsdbst , 'PARAMS', None,
                        {'strings':{'ParamID':paramidst}})

    val = rowdi[rowdi['Datatype']]
    return val

def writeOption(paramidst, scopest, newparamvalst):

    # firstly determine the param-datatype and set the databases
    if scopest == 'db':
        rowdi = pardb.readDictFromParams('', 'PARAMS', None,
                        {'strings':{'ParamID':paramidst}})
        dbst = ''

    elif scopest == 'sys':
        rowdi = pardb.readDictFromParams(db_species.settingsdbst , 'PARAMS', None,
                        {'strings':{'ParamID':paramidst}})
        dbst = db_species.settingsdbst

    datatypest = rowdi['Datatype']
    valst = newparamvalst

    # then write the new value
    if datatypest == 'STRINGS':
        pardb.updateFromParams(dbst, 'PARAMS',{'strings':{datatypest:valst}},
            {'strings':{'ParamID':paramidst}})
    elif datatypest == 'INTEGERS':
        pardb.updateFromParams(dbst, 'PARAMS',{'numbers':{datatypest: int(valst)}},
            {'strings':{'ParamID':paramidst}})
    elif datatypest == 'DECIMALS':
        pardb.updateFromParams(dbst, 'PARAMS',{'numbers':{datatypest: float(valst)}},
            {'strings':{'ParamID':paramidst}})
    elif datatypest == 'BOOLEANS':
        pardb.updateFromParams(dbst, 'PARAMS',{'numbers':{datatypest: int(valst)}},
            {'strings':{'ParamID':paramidst}})


def dateCount(datest, incrementit):
    # deprecated - replaced by jotools.dateCountDelta
    dayst = datest[len(datest)-2:]
    dayit = int(dayst)
    frontest = datest[:len(datest)-2]

    newdayst = str(dayit + incrementit)
    if len(newdayst)==1: newdayst = '0' + newdayst

    newdatest = frontest + newdayst
    return newdatest


def calculateMetricFields(sourcequeryst, selcritdi = None, scandepthit=3):
    '''
    UNIT INFO:
    The newly added (in kjx 2.7) relation-fields num-parents, num-children,
    depth left and depth right give usefull info on the existing
    relation-chains.
    '''

    global leftdepthit
    global rightdepthit
    global parentnumit
    global childrennumit


    cursorli = pardb.readFromParams('', sourcequeryst, None, selcritdi)
    relsfieldli = pardb.getFieldList('',sourcequeryst)

    print scandepthit
    print '------------'
    rowtotalit = pardb.rowCountFromParams('', sourcequeryst, None, selcritdi)

    rowit = 0

    for rowli in cursorli:

        leftdepthit = rightdepthit = parentnumit = childrennumit = 0
        idit = rowli[relsfieldli.index('RelID')]
##        print idit

        readTree('Relations',idit, 'leftobjects',0)
        readTree('Relations',idit, 'rightobjects',0)

        pardb.updateFromParams('', 'Relations',
                    {'numbers':{'Num_parents':parentnumit}},
                    {'numbers':{'RelID':idit}})
        pardb.updateFromParams('', 'Relations',
                    {'numbers':{'Num_children':childrennumit}},
                    {'numbers':{'RelID':idit}})

        if scandepthit > 0:
            readTree('Relations',idit, 'leftobjects',scandepthit)
            readTree('Relations',idit, 'rightobjects',scandepthit)

            pardb.updateFromParams('', 'Relations',
                        {'numbers':{'Depth_left':leftdepthit}},
                        {'numbers':{'RelID':idit}})
            pardb.updateFromParams('', 'Relations',
                        {'numbers':{'Depth_right':rightdepthit}},
                        {'numbers':{'RelID':idit}})

        rowit += 1
        print rowit
##        globrowcount = rowit

        statusmesst = 'From row-total  ' + str(rowtotalit) + '  calculating  ' + str(rowit) + '...'
        jocallback.setStatusBar(statusmesst,1, True)


def readTree(relsqueryst, idit, directionst, maxdepthit):

    '''
    UNIT INFO
    Read all child-recs for parentvalst.
    special params:
        directionst
            query left or right objects

    ADAP NO
    '''


    startcursorli2 = pardb.readFromParams('', relsqueryst,None,
        {'numbers':{'RelID':idit}})

    relsfieldli = pardb.getFieldList('',relsqueryst)
    childvalst = startcursorli2[0][relsfieldli.index('Object2')]
    parentvalst = startcursorli2[0][relsfieldli.index('Object1')]

    if directionst == 'rightobjects':
        readTreeCycle(relsqueryst, childvalst, directionst , maxdepthit, 0,
                relsfieldli)
    elif directionst == 'leftobjects':
        readTreeCycle(relsqueryst, parentvalst, directionst , maxdepthit, 0,
                relsfieldli)


def readTreeCycle(relsqueryst, parentvalst, directionst, maxdepthit, depthit,
        relsfieldli):
    '''
    count metric-variables
    '''
    global leftdepthit
    global rightdepthit
    global parentnumit
    global childrennumit

    # get cursor with root as parent depending on direction
    if directionst == 'rightobjects':
        parentfieldst = 'Object1'
        childfieldst = 'Object2'
    elif directionst == 'leftobjects':
        parentfieldst = 'Object2'
        childfieldst = 'Object1'

    curli2 = pardb.readFromParams('', relsqueryst,None,
        {'strings':{parentfieldst:parentvalst}})

    if maxdepthit > 0:
        if directionst == 'rightobjects':
            if depthit > rightdepthit:
                rightdepthit = depthit
        elif directionst == 'leftobjects':
            if depthit > leftdepthit:
                leftdepthit = depthit

    rowit = 0
    for rowli in curli2:
        # recurse the action conditionally
        if depthit < maxdepthit:
            childvalst = rowli[relsfieldli.index(childfieldst)]
            readTreeCycle(relsqueryst ,childvalst, directionst,
                 maxdepthit, depthit + 1, relsfieldli)
        rowit = rowit + 1

    if maxdepthit == 0:
        if directionst == 'rightobjects':
            childrennumit = rowit
        elif directionst == 'leftobjects':
            parentnumit = rowit



if __name__ == '__main__':
##    print newObjectAllreadyAdded('pythosdfn editors')
##    calculatePathway('firebird-gebruik','0taak-wortel','leftobjects', 15)

##    print readOption('changes_task_path')

    writeOption('custom_view_2','sys','')
